package com.ruicar.afs.cloud.batch.dayend.process;

import cn.hutool.core.date.DateUtil;
import com.ruicar.afs.cloud.batch.frame.AbsBatchRunner;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.uid.UidGenerator;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import com.ruicar.afs.cloud.common.modules.contract.enums.RepaymentStatusEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.MessageFormat;

/**
 * @description: 罚息数据跑批生成
 * @author: sijun.yu
 * @date: 2020/8/8 11:28
 */
public class PenaltyInterestBatchRunner extends AbsBatchRunner {

    public static final int TOTAL_NUM = 300;
    UidGenerator uidGenerator = SpringContextHolder.getBean(UidGenerator.class);

    @Override
    public void process(String param) {
        Connection contract = this.getConnection("contract");
        try {
            checkPenaltyInterestData(contract);
            savePenaltyInterestDetails(contract);
        }catch (Exception e){
            logger.error("",e);
            this.rollBack(contract);
            throw new AfsBaseException(e.getMessage());
        }finally {
            clean(contract);
        }
    }

    /**
     * 检查罚息数据正确性
     * @param connection
     * @throws Exception
     */
    private void checkPenaltyInterestData(Connection connection){

        // 逾期利率
        PreparedStatement ratePs = null;
        ResultSet rateRs = null;
        try {
            ratePs = connection.prepareStatement("select contract_no from basic_financial_agreement where over_due_rate is null");
            rateRs = ratePs.executeQuery();
            if (rateRs!=null && rateRs.next()){
                String contractNo = rateRs.getString("contract_no");
                logger.error("{}逾期利率为空",contractNo);
                throw new AfsBaseException(contractNo+"逾期利率为空");
            }
        }catch (Exception e){
            logger.error("",e);
            throw new AfsBaseException(e.getMessage());
        }finally {
            clean(ratePs);
            clean(rateRs);
        }

        // 应收租金
        PreparedStatement rentPs = null;
        ResultSet rentRs = null;
        try{
            rentPs = connection.prepareStatement("select contract_no from basic_assets_repayment_plan where receivable_rent is null and due_date <= ?");
            rentPs.setTimestamp(1, DateUtil.endOfDay(batchDateInfo.getBatchDate()).toTimestamp());
            rentRs = rentPs.executeQuery();
            if (rentRs!=null && rentRs.next()){
                String contractNo = rentRs.getString("contract_no");
                logger.error("{}应收租金为空",contractNo);
                throw new AfsBaseException(contractNo+"应收租金为空");
            }
        }catch (Exception e){
            logger.error("",e);
            throw new AfsBaseException(e.getMessage());
        }finally {
            clean(rentRs);
            clean(rentPs);
        }
    }

    /**
     * 获取罚息明细数据
     * @return
     */
    private void savePenaltyInterestDetails(Connection connection){

        String breakPointId =  this.loadBreakPoint();
        Long lastProcessId = Long.parseLong(StringUtils.isEmpty(breakPointId)?"0":breakPointId);
        StringBuilder sql = new StringBuilder();
        sql.append("select plan.contract_no,plan.term_no, plan.asset_type,plan.receivable_rent,plan.actual_rent,cost.over_due_rate,plan.id as planId,plan.due_date,plan.status as planStatus");
        sql.append(" from basic_assets_repayment_plan plan ");
        sql.append("inner join basic_financial_agreement cost on cost.contract_no = plan.contract_no and plan.asset_type = cost.cost_type ");
        sql.append("inner join basic_main_info info on plan.contract_no = info.contract_no and info.contract_status in ('contractEffective','overdue') ");// add by sijun.yu 2020-10-10 逾期和生效
        sql.append("where plan.status <>'REPAID' and plan.due_date <= ?  and plan.id  >? order by plan.id asc ");

        // 插入数据SQL
        StringBuilder insertSql = new StringBuilder();

        insertSql.append("insert into basic_penalty_interest_details(id,contract_no,term_no,cost_type,asset_type,operate_type,date,amount,create_time,del_flag,create_by) ");
        insertSql.append("values(?,?,?,?,?,?,?,?,?,'0','system')");


        // 更新逾期天数
        StringBuilder updateSql = new StringBuilder();
        updateSql.append("update basic_debit_info set current_absolute_overdue = ? ");
        updateSql.append("where contract_no = ? ");

        // 更新逾期状态
        StringBuilder statusSql = new StringBuilder();
        statusSql.append("update basic_repayment_plan set status = 'OVERDUE',current_absolute_overdue = ? ");
        statusSql.append("where id=? ");

        PreparedStatement ps = null;
        ResultSet rs = null;
        Date batchDate = new Date(this.batchDateInfo.getBatchDate().getTime());
        int processCount = 0;
        PreparedStatement insertPs = null;
        PreparedStatement updatePs = null;
        PreparedStatement statusPs = null;
        Long lastPlanId = null;
        try {
            // 插入数据
            insertPs = connection.prepareStatement(insertSql.toString());
            // 更新逾期天数
            updatePs = connection.prepareStatement(updateSql.toString());
            // 更新逾期状态
            statusPs = connection.prepareStatement(statusSql.toString());
            // 查询满足条件数据
            ps = connection.prepareStatement(sql.toString());
            ps.setTimestamp(1,DateUtil.endOfDay(batchDateInfo.getBatchDate()).toTimestamp());
            ps.setLong(2,lastProcessId);
            rs = ps.executeQuery();
            while (rs!=null && rs.next()){
               String contractNo =  rs.getString("contract_no");
               int ternNo = rs.getInt("term_no");
               String assetType = rs.getString("asset_type");
               BigDecimal receivableRent = rs.getBigDecimal("receivable_rent");
               BigDecimal actualRent = rs.getBigDecimal("actual_rent");
               BigDecimal overDueRate = rs.getBigDecimal("over_due_rate");
               lastPlanId = rs.getLong("planId");
               Date dueDate = rs.getDate("due_date");
               String planStatus = rs.getString("planStatus");
               Assert.isTrue(AfsEnumUtil.getEnum(planStatus, RepaymentStatusEnum.class)!=null, MessageFormat.format("合同号[{0}]ID为[{1}]的还款计划表,还款状态有误（与代码中定义不一致）",contractNo,lastPlanId.toString()));
               long  days = DateUtil.betweenDay(dueDate,batchDate,true);
               Assert.isTrue(receivableRent.subtract(actualRent).compareTo(BigDecimal.ZERO)>=0, MessageFormat.format("合同号[{0}]ID为[{1}]的还款计划表状态异常(本金已还大于应收)",contractNo,lastPlanId.toString()));
               BigDecimal amount = receivableRent.subtract(actualRent).multiply(overDueRate).divide(new BigDecimal(36000),2,BigDecimal.ROUND_HALF_UP);
                // 插入数据
                insertPs.setLong(1,uidGenerator.getUID());
                insertPs.setString(2,contractNo);
                insertPs.setInt(3,ternNo);
                insertPs.setString(4,"penalty");
                insertPs.setString(5,assetType);
                insertPs.setString(6,"newArrears");
                insertPs.setDate(7,batchDate);
                insertPs.setBigDecimal(8,amount);
                insertPs.setDate(9,batchDate);
                insertPs.addBatch();
                // 更新借据信息
                updatePs.setLong(1,days + 1);
                updatePs.setString(2,contractNo);
                updatePs.addBatch();
                // 更新逾期状态
                statusPs.setLong(1,days + 1);
                statusPs.setLong(2, lastPlanId);
                statusPs.addBatch();
                processCount++;
                if(processCount %TOTAL_NUM == 0){
                    insertPs.executeBatch();
                    updatePs.executeBatch();
                    statusPs.executeBatch();
                    connection.commit();
                    insertPs.clearBatch();
                    updatePs.clearBatch();
                    statusPs.clearBatch();
                    saveBreakPoint(String.valueOf(lastPlanId));
                    processCount= 0;
                }
            }
            // 插入数据，更新借据信息，更新逾期状态
            if(processCount %TOTAL_NUM != 0){
                insertPs.executeBatch();
                updatePs.executeBatch();
                statusPs.executeBatch();
                connection.commit();
                saveBreakPoint(String.valueOf(lastPlanId));
            }
        }catch (Exception e){
            logger.error("",e);
            rollBack(connection);
            throw new AfsBaseException(e.getMessage());
        }finally {
            clean(rs);
            clean(ps);
            clean(insertPs);
            clean(updatePs);
            clean(statusPs);
        }
    }

}
